package com.hontech.bv.conn

import com.hontech.bv.codec.encodeUint16
import com.hontech.bv.codec.encodeUint8
import com.hontech.bv.codec.xorSum
import com.hontech.bv.conn.serial.SerialType

object Proto {
    const val HEAD0 = 0xE1
    const val HEAD1 = 0x1E

    const val HEAD = 0xE11E
    const val END = 0xEF

    const val TYPE_REQUEST = 0x00
    const val TYPE_RESPONSE = 0x01
    const val TYPE_NOTIFY = 0x02

    const val ID_IPC = 0
    const val ID_MASTER = 1
    const val ID_ICE = 2
    const val ID_PICK = 3
    const val ID_HEAT = 4
    const val ID_ARM = 5
    const val ID_POWDER = 6
    const val ID_PEARL = 7

    fun nameId(id: Int): String {
        return when (id) {
            ID_IPC -> "工控机"
            ID_MASTER -> "流水线控制板"
            ID_ICE -> "制冰机控制板"
            ID_PICK -> "取物门控制板"
            ID_HEAT -> "加热控制板"
            ID_ARM -> "机械臂控制板"
            ID_POWDER -> "粉料架控制板"
            ID_PEARL -> "珍珠架控制板"
            else -> "未知控制板"
        }
    }

    const val REQ_ACK = 0x00
    const val REQ_GET_TASK = 0x01
    const val REQ_LOG = 0x02

    const val REQ_OTA_START = 0x03
    const val REQ_OTA_TRANSLATE = 0x04
    const val REQ_OTA_COMPLETE = 0x05
    const val REQ_PING = 0x06
    const val REQ_PRE_PROCESS = 0x07

    const val REQ_STATUS = 0x08

    const val REQ_MASTER_DROP_CUP = 0x09
    const val REQ_MASTER_PIPELINE = 0x0A

    const val REQ_ICE_DRAW_CTRL = 0x0B
    const val REQ_ICE_MAKE_CTRL = 0x0C
    const val REQ_ICE_PARTS_CTRL = 0x0D

    const val REQ_PICK_INIT = 0x0E
    const val REQ_PICK_DOOR_CTRL = 0x0F
    const val REQ_PICK_LED_CTRL = 0x10
    const val REQ_PICK_DO = 0x11

    const val REQ_HEAT_DRAW_CTRL = 0x12
    const val REQ_HEAT_STIR_BOX_CTRL = 0x13
    const val REQ_HEAT_WATER_MOTOR_CTRL = 0x14
    const val REQ_HEAT_ICE_MOTOR_CTRL = 0x15
    const val REQ_HEAT_PARTS_CTRL = 0x16
    const val REQ_HEAT_INIT = 0x17
    const val REQ_HEAT_SET_FLOW = 0x18
    const val REQ_HEAT_GET_FLOW = 0x19
    const val REQ_HEAT_DRAW_WATER = 0x1A
    const val REQ_HEAT_PRE_HEAT = 0x1B
    const val REQ_HEAT_DROP_STEAM = 0x1C
    const val REQ_HEAT_STIR_POWDER = 0x1D

    const val REQ_ARM_ELEVATOR_CTRL = 0x1E
    const val REQ_ARM_JAW_CTRL = 0x1F
    const val REQ_ARM_ARM_CTRL = 0x20
    const val REQ_ARM_ARM_RUN = 0x21
    const val REQ_ARM_FILM_CTRL = 0x22
    const val REQ_ARM_PICK = 0x23
    const val REQ_ARM_INIT = 0x24

    const val REQ_POWDER_UPDOWN_CTRL = 0x25
    const val REQ_POWDER_DUMP_CTRL = 0x26
    const val REQ_POWDER_MOVE_CTRL = 0x27
    const val REQ_POWDER_CARGO_CTRL = 0x28
    const val REQ_POWDER_PDE_CTRL = 0x29
    const val REQ_POWDER_INIT = 0x2A
    const val REQ_POWDER_PICK = 0x2B

    const val REQ_ICE_DROP_ICE = 0x2C

    const val REQ_HEAT_CLEAN = 0x2D
    const val REQ_HEAT_PRE_WATER = 0x2E

    const val REQ_ARM_RUN_POSITION = 0x2F

    const val REQ_PEARL_UPDOWN_CTRL = 0x30
    const val REQ_PEARL_DUMP_CTRL = 0x31
    const val REQ_PEARL_MOVE_CTRL = 0x32
    const val REQ_PEARL_CARGO_CTRL = 0x33
    const val REQ_PEARL_PDE_CTRL = 0x34
    const val REQ_PEARL_INIT = 0x35
    const val REQ_PEARL_PICK = 0x36

    const val REQ_PIPE_LINE_PICK = 0x37
    const val REQ_PEARL_NEXT = 0x38
    const val REQ_PIPE_LINE_LED = 0x39
    const val REQ_PIPE_LINE_ELOCK = 0x3A

    const val REQ_PICK_NOTIFY = 0x3E

    fun nameReq(req: Int): String {
        return when (req) {
            REQ_ACK -> "ACK"
            REQ_LOG -> "LOG"
            REQ_OTA_START -> "OTA Start"
            REQ_OTA_TRANSLATE -> "OTA Translate"
            REQ_OTA_COMPLETE -> "OTA Complete"
            REQ_PING -> "Ping"
            REQ_PRE_PROCESS -> "预处理"
            REQ_PICK_LED_CTRL -> "取物门LED控制"
            REQ_PICK_DOOR_CTRL -> "取物门控制"
            else -> "未知协议"
        }
    }

    fun progName(prog: Int): String {
        return when(prog) {
            1 -> "开始"
            2 -> "落杯"
            3 -> "取物门初始化"
            4 -> "机械臂初始化"
            5 -> "加热初始化"
            6 -> "启动粉料货架"
            7 -> "启动珍珠货架"
            8 -> "机械臂运动到落杯1位置"
            9 -> "机械臂运动到检杯位置"
            10 -> "机械臂运动到倒珍珠位置"
            11 -> "等待珍珠就绪"
            12 -> "倒珍珠"
            13 -> "珍珠货架复位"
            14 -> "机械臂运动到落冰位置"
            15 -> "落冰"
            16 -> "机械臂运动到出奶茶位置"
            17 -> "等待奶茶就绪"
            18 -> "开启夹管阀"
            19 -> "启动清洗"
            20 -> "机械臂运动到封膜位置"
            21 -> "封膜"
            22 -> "机械臂运动到取物口2，并复位"
            23 -> "结束"
            24 -> "取物门1打开"
            25 -> "取物门2打开"
            26 -> "取物门1等待取货"
            27 -> "取物门2等待取货"
            28 -> "取物门1关门"
            29 -> "取物门2关门"
            else -> "未知进度"
        }
    }

    fun parse(buf: ByteArray, offset: Int, args: Array<SerialType>) {
        var index = offset
        for (arg in args) {
            arg.decode(buf, index)
            index += arg.size()
        }
    }

    private fun setConnInfo(buf: ByteArray, req: Int, dest: Int, seq: Int, type: Int) {
        encodeUint16(buf, 0, HEAD)
        encodeUint8(buf, 2, buf.size)
        encodeUint8(buf, 3, req)
        encodeUint8(buf, 4, (seq shl 4) + type)
        encodeUint8(buf, 5, (ID_IPC shl 4) + dest)

        val s = buf.xorSum(6, buf.size - 8)
        encodeUint8(buf, buf.size - 2, s)
        encodeUint8(buf, buf.size - 1, END)
    }

    fun makeAck(dest: Int, seq: Int): ByteArray {
        val buf = ByteArray(8)
        setConnInfo(buf, REQ_ACK, dest, seq, TYPE_RESPONSE)
        return buf
    }

    fun makeRequest(req: Int, dest: Int, seq: Int, args: Array<SerialType>): ByteArray {
        var argLen = 0
        for (arg in args) {
            argLen += arg.size()
        }
        val buf = ByteArray(argLen + 8)

        var index = 6
        for (arg in args) {
            arg.encode(buf, index)
            index += arg.size()
        }

        setConnInfo(buf, req, dest, seq, TYPE_REQUEST)

        return buf
    }

}